var IncrementalTableInputMethod = InputMethod.extend({
	need_unicode_convert: true,
	/* max_key_length: (integer)
           maximum length of preedit (If the preedit length reachs this value, onComplete is called)
        */
	max_key_length: 0,
        // internal used for selection choice list
	current_list: null,
	target_list: 'Num',

	// reference to a GFCandidateList object
	candlist: null,

	jump_stack: null,
	current_index: 0,
	current_count: 0,

	min_count: 20,

	constructor: function()
	{
		this.base();
		var key;
		// convert the char map
		if(this.need_unicode_convert) {
			for(key in this.GetClass().char_map) {
				this.GetClass().char_map[key] = lib.utf16char(this.GetClass().char_map[key]);
			}
		}
	},
	init_module: function(ime,modman)
	{
		if(!this.base(ime,modman)) return false;
		return true;
	},
	module_name: function()
	{
		return 'IncrementalTableInputMethod';
	},
	IMName: function()
	{
		return "IncrementalTableInputMethod";
	},
	IsDisplayModeSupported: function(mode)
	{
		if(mode == GownFullState.MODE_ROOT) return true;
		else if(mode == GownFullState.MODE_OVERTHESPOT) return true;
		else return false;
	},
	onResetPreedit: function(mode)
	{
		this.onCancel();
	},
	keydown_handler: function(obj,key)
	{
		var b = true;
		switch(key) {
 		case 27: // Escape
			this.ime.ResetPreedit();
			b = false;
			break;
		case 8: // Backspace
			b = !this.onDeletePreedit(obj);
			break;
		default:
			break;
		}
		return b;
	},
	keypress_handler: function(obj,key,m)
	{
		var b = true;

		if(m != 0) return true;

		switch(key) {
		case 32: // Space
			if(this.candlist) {
				this.candlist.onNextPage(obj);
				b = false;
			}
			if(this.ime.GetPreeditLength() > 0) {
				this.onComplete(obj);
				b = false;
			}
			break;
		default:
			break;
		}

		if(!b) return false;

//		if(this.candlist) return false;

		if(this.ime.GetPreeditLength() >= this.max_key_length) return false;
		else {
			var ch = String.fromCharCode(key);
			var dch = this.GetClass().char_map[ch];
			var index = this.GetClass().index;
			var next_index;
			var preedit = this.ime.GetPreedit();

			if(dch) {
				if(this.current_index <= 0) {
					this.current_index = (index[ch])['@'];
					if(!this.current_index) {
						Debug.trace(1,"IncrementalTableInputMethod: no index for the this key.");
						this.current_index = 0;
						return false;
					}
					this.current_count = (index[ch])['#'];
				}
				else {
					next_index = (index[preedit])[ch];
					if(!next_index) {
						Debug.trace(1,"IncrementalTableInputMethod: no index for the this key.");
						return false;
					}
					this.current_count = (index[preedit+ch])['#'];
					if(!this.current_count) this.current_count = 0;
					this.jump_stack.push(this.current_index);
					this.current_index = next_index;
				}
				this.ime.AppendPreedit(ch,dch,obj);
				Debug.trace(1,"IncrementalTableInputMethod: Append Preedit (%s,%s)",ch,dch);
				this.UpdateCandidate();
			}
			else {
				if(this.ime.GetPreeditLength() > 0) return false;
				else return true;
/*					if(this.IsSelectionPreedit()) this.onSelectionModeResetPreedit();
					return true;
*/
			}
			return false;
		}
	},
	onActive: function()
	{
		this.current_list = null;
		this.current_index = 0;
		this.jump_stack = new Array();
	},
	onDeactive: function()
	{
		this.current_list = null;
		this.jump_stack = null;
	},
	onDeletePreedit: function(obj)
	{
		if(this.ime.GetPreeditLength() > 0) {
			this.ime.DeletePreedit(1,1,obj);
			if(this.jump_stack.length > 0) this.current_index = this.jump_stack.pop();
			else this.current_index = 0;
			this.UpdateCandidate();
			return true;
		}
		else return false;
	},
	onCancel: function(obj)
	{
		this.ime.ResetPreedit();
		this.current_list = null;
		this.jump_stack = new Array();
		this.current_index = 0;
		this.UpdateCandidate();
	},
	ListSelectHandler: function(obj,pos)
	{
		var ch;

		ch = this.current_list[pos];
		this.current_list = null;
		this.jump_stack = new Array();
		this.current_index = 0;
		this.ime.ResetPreedit();
		this.UpdateCandidate();

		this.ime.SendString(obj,ch);
		return true;
	},
	UpdateCandidate: function()
	{
		var x = this;

		if(this.current_index > 0) {
			var index = this.GetClass().index;
			var data = this.GetClass().data;
			var ch,i,count,maxbound;
			var update = true;

			count = this.current_count;
			count = (count < this.min_count) ? this.min_count : count;
			maxbound = ((this.current_index + count) > data.length) ? data.length : (this.current_index + count);
			this.current_list = new Array();
			for(i=this.current_index;i<maxbound;i++) {
				ch = data[i];
				if(this.need_unicode_convert) {
					if(GownFullBrowserDetect.isUnicodeVisible(ch)) this.current_list.push(lib.utf16char(ch));
					else {
						Debug.present && Debug.trace(2,'IncrementalTableInputMethod: isUnicodeVisible filtered u+%x',ch);
					}
				}
				else this.current_list.push(ch);
			}

			if(!this.candlist) {
				this.candlist = this.ime.candwin.OccupyList(this,this.target_list);
				update = false;
			}
			if(!this.candlist) {
				Debug.present && Debug.trace(0,'SimpleTableInputMethod: Require Target list %s is not available.',this.target_list);
				return;
			}
			
			if(update) {
				this.candlist.UpdateList(this.current_list);
			}
			else {
				this.candlist.ResetList();
				this.candlist.SetList(null,this.current_list,function(obj,pos) { return x.ListSelectHandler(obj,pos); });
				this.candlist.SetCancelHandler(function() { x.onCancel(null); return true; });
			}
			this.ime.candwin.UpdateCandidate();
		}
		else {
			if(this.candlist) {
				this.ime.candwin.ReleaseList(this,this.target_list);
				this.candlist = null;
			}
			this.ime.candwin.SetStatus(null);
			this.ime.candwin.UpdateCandidate();
		}
	},
	onComplete: function(obj)
	{
		this.ListSelectHandler(obj,1);
		return true;
	}
});
